﻿//#define DEBUG

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System;
/*
负责游戏的逻辑和UI更新
*/
public class GameManager : MonoBehaviour
{
    // 游戏组件 UI相关
    public GameObject cardPref;
    public GameObject playerCardTable;
    public GameObject oppCardTable;
    public GameObject repCardTable;
    public GameObject cardNumText;
    public GameObject aiMoveText;
    public GameObject hintText;
    public GameObject playerScoreText, oppScoreText;
    public GameObject playerWinCountText, oppWinCountText;
    public GameObject turnCountText;
    public Button buttonOK;
    public Button buttonCancel;
    public Button buttonOver;
    public Button buttonDeal;
    public AudioSource buttonClickAudio;

    private int MAX_CARD_HOLD = 5; // 最多持有牌数
    private int MAX_CARD_REP = 5; // 最多可换牌数
    private int OVER_THRESHOLD_SCORE_BASE = 20; // 结束阈值
    private int PRESS_THRESHOLD_SCORE_BASE = 30; // 压制阈值

    public List<int> repCard { set; get; } // 可换牌
    private Stack<int> cardPile { set; get; } // 可用牌
    private Dictionary<GameObject, List<int>> cardRecord; // 记录玩家和卡牌

    private GameStatus lastStatus;
    public GameStatus status;  // 初始状态

    private float cardSprtScale = 2.5f; // 牌的缩放

    private int PLAYER_NUMBER = 2; // 玩家总数
    private bool showOppCards;
    private int localPlayerNumber; // 运行本程序的玩家序号
    private int currentPlayerNumber; // 当前玩家序号
    private int lastWinnerNumber;
    private int playerScore, oppScore; // 每个玩家的总得分
    private int playerWin, oppWin;
    private int turnNumber;
    private PressStatus pressStatus;

    public enum PressStatus
    {
        PlayerPressOpp,
        OppPressPlayer,
        None
    }

    public enum CardType
    {
        Heart,
        Spade,
        Club,
        Diamond,
        SmallJoker,
        BigJoker,
    }

    public enum GameStatus
    {
        Start, // 发牌阶段
        WaitForPlayer, // 等待用户选择行动状态
        PlayerDealAndPut, // 抽牌出牌状态
        PlayerSwap, // 等待玩家选择换入换出的牌的状态
        WaitForAI,
        PressOrNot, // 询问是否压制
        Over // 结束状态
    }
    // UI更新
    void OnGUI()
    {
        SetButtons();
        SetDisplayArea();
    }
    void Start()
    {
        PLAYER_NUMBER = 2;
        localPlayerNumber = 0;
        lastWinnerNumber = 0;
        playerScore = 0;
        oppScore = 0;
        playerWin = 0;
        oppWin = 0;
        currentPlayerNumber = 0;
        turnNumber = 0;
        lastStatus = GameStatus.Over;
        status = GameStatus.Start;
    }
    // Update is called once per frame
    void Update()
    {

        if (lastStatus == status)
            return;
        lastStatus = status;
        switch (status)
        {
            case GameStatus.Start:
                InitVars();
                GenerateCards();
                SetDisplayArea();
                InitialCardDeal();
                SetButtons();
                turnCountText.GetComponent<Text>().text = "第<color=red>" + turnNumber + "</color>局";
                if (currentPlayerNumber == 0)
                    status = GameStatus.WaitForPlayer;
                if (currentPlayerNumber == 1)
                    status = GameStatus.WaitForAI;
                break;
            case GameStatus.WaitForPlayer:
                // 使能选牌
                EnableCardChoose(playerCardTable);
                DisableCardChoose(oppCardTable);
                DisableCardChoose(repCardTable);
                // 使能按钮
                EnableButton(buttonDeal);
                EnableButton(buttonOver);
                DisableButton(buttonCancel);
                DisableButton(buttonOK);
                break;

            case GameStatus.PlayerDealAndPut:
                // 使能选牌
                EnableCardChoose(playerCardTable);
                DisableCardChoose(oppCardTable);
                DisableCardChoose(repCardTable);
                // 使能按钮
                DisableButton(buttonOK);
                DisableButton(buttonOver);
                DisableButton(buttonDeal);
                DisableButton(buttonCancel);
                break;
            case GameStatus.PlayerSwap:
                // 使能选牌
                EnableCardChoose(playerCardTable);
                DisableCardChoose(oppCardTable);
                // 根据可换牌堆是否满
                if (IsRepFull())
                    EnableCardChoose(repCardTable);
                else
                    DisableCardChoose(repCardTable);
                // 使能按钮
                EnableButton(buttonDeal);
                EnableButton(buttonCancel);
                DisableButton(buttonOver);
                if (repCard.Count == 1)
                    EnableButton(buttonOK);
                else
                    DisableButton(buttonOK);
                break;
            case GameStatus.WaitForAI:
                // 禁用所有卡牌选取
                DisableCardChoose(playerCardTable);
                DisableCardChoose(oppCardTable);
                DisableCardChoose(repCardTable);
                // 禁用所有按钮
                DisableButton(buttonOK);
                DisableButton(buttonCancel);
                DisableButton(buttonDeal);
                DisableButton(buttonOver);
                AIMove();
                break;
            case GameStatus.PressOrNot:
                if (currentPlayerNumber == 1)
                {
                    AIPress();
                    status = GameStatus.Over;
                }
                else
                {
                    // 禁用所有卡牌选取
                    DisableCardChoose(playerCardTable);
                    DisableCardChoose(oppCardTable);
                    DisableCardChoose(repCardTable);
                    // 按钮
                    EnableButton(buttonOK);
                    EnableButton(buttonCancel);
                    DisableButton(buttonDeal);
                    DisableButton(buttonOver);
                    hintText.GetComponent<Text>().text = "电脑结束了这局，你是否压它？\n确定/取消";
                }

                break;
            case GameStatus.Over:
                // 禁用所有卡牌选取
                DisableCardChoose(playerCardTable);
                DisableCardChoose(oppCardTable);
                DisableCardChoose(repCardTable);
                // 按钮
                EnableButton(buttonOK);
                EnableButton(buttonCancel);
                DisableButton(buttonDeal);
                DisableButton(buttonOver);
                // 实际分数需要减去MAX_CARD_HOLD * 100以去除加权牌分
                int s0 = Utility.ScoreOfCardGroup(cardRecord[playerCardTable]) - MAX_CARD_HOLD * 100;
                int s1 = Utility.ScoreOfCardGroup(cardRecord[oppCardTable]) - MAX_CARD_HOLD * 100;
                // 小于0(相同牌数小于MAX_CARD_HOLD张)，分数为0，大于0不变
                s0 = Math.Max(0, s0); 
                s1 = Math.Max(0, s1);
                if (s0 < s1)
                {
                    hintText.GetComponent<Text>().text = "你输了:(。\n比分为" + s0 + "(你) : " + s1 + "(电脑)";
                    lastWinnerNumber = 1;
                    oppWin++;
                    if (pressStatus != PressStatus.None)
                    {
                        s1 += s0;
                        s0 = 0;
                    }
                }
                else if (s0 > s1)
                {
                    hintText.GetComponent<Text>().text = "你赢了(づ￣ 3￣)づ。\n比分为" + s0 + "(你) : " + s1 + "(电脑)";
                    lastWinnerNumber = 0;
                    playerWin++;
                    if (pressStatus != PressStatus.None)
                    {
                        s0 += s1;
                        s1 = 0;
                    }
                }
                else // 分数相等
                {
                    if (pressStatus == PressStatus.PlayerPressOpp)
                    {
                        hintText.GetComponent<Text>().text = "你输了:(。\n比分为" + s0 + "(你) : " + s1 + "(电脑)";
                        lastWinnerNumber = 1;
                        oppWin++;
                    }
                    else if (pressStatus == PressStatus.OppPressPlayer)
                    {
                        hintText.GetComponent<Text>().text = "你赢了(づ￣ 3￣)づ。\n比分为" + s0 + "(你) : " + s1 + "(电脑)";
                        lastWinnerNumber = 0;
                        playerWin++;
                    }
                    else
                    {
                        hintText.GetComponent<Text>().text = "平局。\n比分为" + s0 + "(你) : " + s1 + "(电脑)";                        
                    }
                }
                showOppCards = true;
                UpdateCardsOf(oppCardTable);
                playerScore += s0;
                oppScore += s1;

                repCard.Clear();
                UpdateCardsOf(repCardTable);

                playerScoreText.GetComponent<Text>().text = "总得分：" + playerScore + "分";
                oppScoreText.GetComponent<Text>().text = "总得分：" + oppScore + "分";
                playerWinCountText.GetComponent<Text>().text = "胜率：" + 100 * playerWin / turnNumber + "%";
                oppWinCountText.GetComponent<Text>().text = "胜率：" + 100 * oppWin / turnNumber + "%";

                hintText.GetComponent<Text>().text += "\n<color=red>是否开始下一局？</color>\n确定/取消";
                break;

        }

        if (cardPile.Count == 0)
            status = GameStatus.Over;
        // update card number
        cardNumText.GetComponent<Text>().text = "牌堆尚有：<color=red>" + cardPile.Count + "</color>张";

    }
    // 初始化变量
    void InitVars()
    {
        showOppCards = false;
        currentPlayerNumber = lastWinnerNumber;
        lastStatus = GameStatus.Over;
        status = GameStatus.Start;
        pressStatus = PressStatus.None;
        hintText.GetComponent<Text>().text = "";
        aiMoveText.GetComponent<Text>().text = "";
        turnNumber++;
    }
    // 生成牌堆
    void GenerateCards()
    {
        cardPile = new Stack<int>();
        repCard = new List<int>();

        List<int> indice = new List<int>();
        for (int i = 0; i < 54; i++)
        {
            indice.Add(i);
        }
        // shuffle algorithm
        // 1. randomly selected index i from indice[...]
        // 2. add Card[i] to card pile
        // 3. remove i from indice[...]
        // 4. return to step 1 until all the cards are added
        for (int i = 54; i > 0; i--)
        {
            int index = UnityEngine.Random.Range(0, i);
            int card = indice[index];
            indice.RemoveAt(index);
            cardPile.Push(card);
        }
    }
    // 初始发牌操作
    void InitialCardDeal()
    {
        cardRecord = new Dictionary<GameObject, List<int>>();
        cardRecord[playerCardTable] = new List<int>();
        cardRecord[oppCardTable] = new List<int>();
        repCard = new List<int>();
        cardRecord[repCardTable] = repCard;
 
        for (int i = 0; i < MAX_CARD_HOLD; i++)
        {
            DealCardTo(playerCardTable);
        }
        for (int i = 0; i < MAX_CARD_HOLD; i++)
        {
            DealCardTo(oppCardTable);
        }
    }
    #region 牌UI相关的所有操作
    // 设置牌显示区域范围
    void SetDisplayArea()
    {
        HorizontalLayoutGroup hlg = null;

        hlg = playerCardTable.GetComponent<HorizontalLayoutGroup>();
        Vector2 bound = GetCardSize();
        hlg.spacing = 1.1f * bound.x;
        // 布局起点位置
        var mid_pos = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width / 2, 0, 0));
        mid_pos.x -= MAX_CARD_HOLD/2 * bound.x;
        mid_pos.y += 0.5f * bound.y;
        playerCardTable.transform.position = mid_pos;

        hlg = oppCardTable.GetComponent<HorizontalLayoutGroup>();
        hlg.spacing = 1.1f * bound.x;
        // 布局起点位置
        mid_pos = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width / 2, Screen.height, 0));
        mid_pos.x -= MAX_CARD_HOLD / 2 * bound.x;
        mid_pos.y -= 0.5f * bound.y;
        oppCardTable.transform.position = mid_pos;

        hlg = repCardTable.GetComponent<HorizontalLayoutGroup>();
        hlg.spacing = 1.1f * bound.x;
        // 布局起点位置
        mid_pos = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width / 2, Screen.height / 2, 0));
        mid_pos.x -= MAX_CARD_HOLD / 2 * bound.x;
        repCardTable.transform.position = mid_pos;
    }
    // 获取牌的长宽尺寸，用于计算布局信息
    Vector2 GetCardSize()
    {
        Sprite sp = Resources.Load("Cards/rear", typeof(Sprite)) as Sprite;
        Vector2 b = 2.0f * sp.bounds.extents;
        b *= cardSprtScale;

        return b;
    }
    // 设置按钮位置
    void SetButtons()
    {
        List<Button> lb = new List<Button>();
        lb.Add(buttonOK);
        lb.Add(buttonCancel);
        lb.Add(buttonDeal);
        lb.Add(buttonOver);

        for (int i = 0; i < lb.Count; i++)
        {
            float x = Screen.width / 2 + (i * 10 - 15) * 60 / 10;

            Vector3 pos = new Vector3(x, Screen.height * 2 / 7, 0);
            lb[i].transform.position = pos;
        }
    }
    // 给指定玩家发牌
    public void DealCardTo(GameObject go)
    {
        cardRecord[go].Add(cardPile.Pop());
        UpdateCardsOf(go);
    }
    // 玩家出一张牌
    public void DropCard(GameObject go, int index)
    {
        int code = RemoveCardFrom(go, index);
        cardRecord[repCardTable].Add(code);
        UpdateCardsOf(repCardTable);
    }
    // 将指定的(使用卡片下标)卡片加入从指定的玩家手中删除
    // 返回删除的卡片的code
    int RemoveCardFrom(GameObject go, int index)
    {
        int ret = cardRecord[go][index];
        List<int> cards = cardRecord[go]; // 获取玩家的卡片数据
        cards.RemoveAt(index);
        UpdateCardsOf(go);
        return ret;
    }
    // 根据指定玩家的牌的内存数据更新卡牌UI
    // 每次都会把牌排序
    void UpdateCardsOf(GameObject go)
    {
        List<int> cards = cardRecord[go];
        cards.Sort();
        // 先移除所有卡牌
        RemoveAllCardsFrom(go);
        // 再依次添加卡牌
        for (int i = 0; i < cards.Count; i++)
        {
            AddCardToPlayer(go, cards[i]);
        }
    }
    // 删除指定玩家的所有的卡牌
    void RemoveAllCardsFrom(GameObject go)
    {
        List<SpriteRenderer> sr = new List<SpriteRenderer>();
        go.GetComponentsInChildren(sr);
        foreach (var s in sr)
            Destroy(s.gameObject);
    }
    // 将指定的卡片UI加入到指定玩家手中（基于牌的编码）
    void AddCardToPlayer(GameObject go, int code)
    {
        GameObject c = Instantiate(cardPref) as GameObject;
        Sprite sp = GetCardSprite(code);
        if (!showOppCards && go == oppCardTable)
            sp = GetCardSprite(54); 

        c.GetComponent<SpriteRenderer>().sprite = sp;
        c.transform.localScale = new Vector3(cardSprtScale, cardSprtScale, cardSprtScale);
        c.transform.SetParent(go.transform);
        c.GetComponent<BoxCollider2D>().size = 2.0f * sp.bounds.extents;
        c.GetComponent<Card>().cardOwner = go;
        c.GetComponent<Card>().chosen = false;
        c.GetComponent<Card>().code = code;
    }
    // 加载指定编号的卡牌外形
    Sprite GetCardSprite(int code)
    {
        string resPath = null;
        if (code == 54)
            resPath = "Cards/rear";
        else if (code == 53)
            resPath = "Cards/Joker/bigjoker";
        else if (code == 52)
            resPath = "Cards/Joker/smalljoker";
        else
        {
            int type = code / 13;
            switch (type)
            {
                case 0:
                    resPath = "Cards/Heart/Heart_" + string.Format("{0:D2}", code % 13 + 1);
                    break;
                case 1:
                    resPath = "Cards/Spade/Spade_" + string.Format("{0:D2}", code % 13 + 1);
                    break;
                case 2:
                    resPath = "Cards/Club/Club_" + string.Format("{0:D2}", code % 13 + 1);
                    break;
                case 3:
                    resPath = "Cards/Diamond/Diamond_" + string.Format("{0:D2}", code % 13 + 1);
                    break;
            }
        }
        if (resPath != null)
            return Resources.Load(resPath, typeof(Sprite)) as Sprite;
        else
            return null;
    }    
    // 使能当前玩家的牌选
    public void EnableCardChoose(GameObject go)
    {
        foreach (var chd in go.GetComponentsInChildren<BoxCollider2D>())
        {
            chd.enabled = true;
        }
    }
    // 失能当前玩家的牌选
    public void DisableCardChoose(GameObject go)
    {
        foreach (var chd in go.GetComponentsInChildren<BoxCollider2D>())
        {
            chd.enabled = false;
        }
    }
    // 使能指定按钮
    public void EnableButton(Button b)
    {
        b.interactable = true;
    }
    // 失能指定按钮
    public void DisableButton(Button b)
    {
        b.interactable = false;
    }
    #endregion
    #region 游戏的相关状态的函数封装
    // 可换牌是否已满
    public bool IsRepFull()
    {
        return repCard.Count == MAX_CARD_REP;
    }
    #endregion
    #region 按钮响应函数
    // 抽牌
    public void OnBtnDealClick()
    {
        buttonClickAudio.Play();
        DealCardTo(playerCardTable);
        // 牌堆满的情况下点击抽牌 会清空已有可换牌
        if (IsRepFull())
        {
            repCard.Clear();
            UpdateCardsOf(repCardTable);
        }
        status = GameManager.GameStatus.PlayerDealAndPut;
    }
    // 确定
    public void OnBtnOKClick()
    {
        buttonClickAudio.Play();
        if (status == GameStatus.PressOrNot)
        {
            status = GameStatus.Over;
            pressStatus = PressStatus.PlayerPressOpp;
        }
        else if (status == GameStatus.Over)
        {
            status = GameStatus.Start;
        }
        else
        {
            List<int> dropCards = GetDropCards(); // 想出的牌编号

            List<int> wantCards = GetWantCards(); // 想要的牌编号  

            ReplaceCard(dropCards, wantCards, playerCardTable);

            status = GameStatus.WaitForAI;
            currentPlayerNumber = (currentPlayerNumber + 1) % PLAYER_NUMBER;
        }
    }
    // 取消
    public void OnBtnCancelClick()
    {
        buttonClickAudio.Play();
        if (status == GameStatus.Over)
        {
            Application.Quit();
        }
        else if (status == GameStatus.PressOrNot)
        {
            pressStatus = PressStatus.None;
            status = GameStatus.Over;
        }
        else
        {
            ResetAllCardsChosen();
        }
    }
    // 结束
    public void OnBtnOverClick()
    {
        buttonClickAudio.Play();
        ResetAllCardsChosen();
        status = GameStatus.PressOrNot;
        currentPlayerNumber = (currentPlayerNumber + 1) % PLAYER_NUMBER;
    }
    // 重置所有牌为未选中
    void ResetAllCardsChosen()
    {
        List<Card> lc = new List<Card>();
        playerCardTable.GetComponentsInChildren(lc);
        foreach (var c in lc)
        {
            if (c.chosen)
            {
                c.UnChosen();
            }
        }
        repCardTable.GetComponentsInChildren(lc);
        foreach (var c in lc)
        {
            if (c.chosen)
            {
                c.UnChosen();
            }
        }
    }
    // 给定出牌和要牌列表 更新指定玩家的手牌
    void ReplaceCard(List<int> dropCards, List<int> wantCards, GameObject go)
    {
        // 把选中的玩家牌从玩家牌堆中删除后加入可换牌堆
        foreach (var c in dropCards)
        {
            cardRecord[go].Remove(c);
            cardRecord[repCardTable].Add(c);
        }
        // 把选中的可换牌从可换牌堆中删除后加入玩家牌堆
        foreach (var c in wantCards)
        {
            cardRecord[repCardTable].Remove(c);
            cardRecord[go].Add(c);
        }
        UpdateCardsOf(go);
        UpdateCardsOf(repCardTable);

        Card.chosenPlayerCardNum = 0;
        Card.chosenRepCardNum = 0;
    }
    // 返回玩家要出的牌
    List<int> GetDropCards()
    {
        List<int> dropCards = new List<int>();

        Card[] temp = playerCardTable.GetComponentsInChildren<Card>(); // 玩家牌
        for (int i = 0; i < temp.Length; i++)
        {
            if (temp[i].chosen)
                dropCards.Add(temp[i].code);
        }

        return dropCards;
    }
    // 返回玩家想要的牌
    // AI不能使用这个API!
    // 点击确定有两种情况: 抽牌出牌和换牌
    List<int> GetWantCards()
    {
        List<int> wantCards = new List<int>();
        // 只有PS状态才返回非空列表
        if (status == GameStatus.PlayerSwap)
        {
            // 牌堆满的时候 只需要1张被选中的
            if (IsRepFull())
            {
                Card[] temp = repCardTable.GetComponentsInChildren<Card>(); // 可换牌
                for (int i = 0; i < temp.Length; i++)
                {
                    if (temp[i].chosen)
                    {
                        wantCards.Add(temp[i].code);
                    }
                }
            }
            // 牌堆没满 所有可换牌都必须加入
            else
            {
                return new List<int>(repCard);
            }
        }
        return wantCards;
    }
    #endregion
    #region AI相关操作
    void AIMove()
    {
        if (AIOver())
        {
            status = GameStatus.PressOrNot;
        }
        // 当牌堆未满时
        else
        {
            if (IsRepFull() == false)
            {
                // 判断是否换牌
                List<int> dropCards = new List<int>();
                AIRepAllOrDeal(dropCards);
                if (dropCards.Count == 0)
                {
                    AIDeal();
                    List<int> dc = AIDrop();
                    aiMoveText.GetComponent<Text>().text = "电脑抽牌并出了" + Utility.CardGroupString(dc);
                }
                else
                {
                    aiMoveText.GetComponent<Text>().text = "电脑用" + Utility.CardGroupString(dropCards) + "\n换了" + Utility.CardGroupString(new List<int>(repCard));
                    ReplaceCard(dropCards, new List<int>(repCard), oppCardTable);
                }
            }
            // 牌堆满了 此时只能换一张
            else
            {
                // 判断是否换牌
                List<int> dropCards = new List<int>();
                List<int> takeCards = new List<int>();
                AIRepOneOrDeal(dropCards, takeCards);
                if (dropCards.Count == 0)
                {
                    AIDeal();
                    List<int> dc = AIDrop();
                    aiMoveText.GetComponent<Text>().text = "电脑抽牌并出了" + Utility.CardGroupString(dc);
                }
                else
                {
                    aiMoveText.GetComponent<Text>().text = "电脑用"+ Utility.CardGroupString(dropCards) + "\n换了"+ Utility.CardGroupString(takeCards);
                    ReplaceCard(dropCards, takeCards, oppCardTable);
                }
            }
            status = GameStatus.WaitForPlayer;
        }
        currentPlayerNumber = (currentPlayerNumber + 1) % PLAYER_NUMBER;
    }
    // 抽牌
    void AIDeal()
    {
        DealCardTo(oppCardTable);
        // 如果此时可换牌满了 就清空
        if (IsRepFull())
        {
            repCard.Clear();
            UpdateCardsOf(repCardTable);
        }
    }
    // AI决定出哪张牌: 遍历所有剩余牌的分数即可
    // 返回出的牌
    List<int> AIDrop()
    {
        // 拷贝手牌
        List<int> cards = new List<int>(cardRecord[oppCardTable]);
        int holdScore = 0;
        int holdNum = MAX_CARD_HOLD; // 手头应该留的牌数量

        // 所有可能的手牌残余
        List<List<int>> holdCardsCandidates = new List<List<int>>();
        GenerateCardsCombines(cards, new List<int>(), 0, holdNum, holdCardsCandidates);

        List<int> holdCards = null;
        // 遍历所有可能的手牌 计算分数
        // 如果分数高于当前最高分 则更新holdCards
        foreach (var hc in holdCardsCandidates)
        {
            int s = Utility.ScoreOfCardGroup(hc);
            if (holdScore < s)
            {
                holdScore = s;
                holdCards = hc;
            }
        }
        List<int> dropCards = new List<int>(cardRecord[oppCardTable]);
        // 从当前手牌中删去和应有手牌中相同的部分（这部分需要保留）
        // 如果之前的搜索不能搜索到更好的结果 则dropCards是一个空List
        foreach (var c in holdCards)
        {
            if (dropCards.Exists(x => x == c))
                dropCards.Remove(c);
        }
        int index = cards.FindIndex(x => x == dropCards[0]);

        DropCard(oppCardTable, index);

        return dropCards;
    }
    // 计算是否应该换牌
    void AIRepAllOrDeal(List<int> dropCards)
    {
        // 拷贝手牌
        List<int> cards = new List<int>(cardRecord[oppCardTable]);
        int holdScore = Utility.ScoreOfCardGroup(cards);
        int holdNum = MAX_CARD_HOLD - repCard.Count; // 手头应该留的牌数量

        // 所有可能的手牌残余
        List<List<int>> holdCardsCandidates = new List<List<int>>();
        GenerateCardsCombines(cards, new List<int>(), 0, holdNum, holdCardsCandidates);

        // 将可换牌堆中的牌加入到手牌中计算分数
        foreach (var hc in holdCardsCandidates)
        {
            // 每张可换牌都要加进去
            foreach (var c in repCard)
                hc.Add(c);
        }
        List<int> holdCards = new List<int>(cardRecord[oppCardTable]);
        // 遍历所有可能的手牌 计算分数
        // 如果分数高于当前最高分 则更新holdCards
        foreach (var hc in holdCardsCandidates)
        {
            int s = Utility.ScoreOfCardGroup(hc);
            if (holdScore < s)
            {
                holdScore = s;
                holdCards = hc;
            }
        }
        List<int> dropCardsCandidates = new List<int>(cardRecord[oppCardTable]);
        // 从当前手牌中删去和应有手牌中相同的部分（这部分需要保留）
        // 如果之前的搜索不能搜索到更好的结果 则dropCardsCandidates是一个空List
        foreach (var c in holdCards)
        {
            if (dropCardsCandidates.Exists(x => x == c))
                dropCardsCandidates.Remove(c);
        }
        for (int i = 0; i < dropCardsCandidates.Count; i++)
            dropCards.Add(dropCardsCandidates[i]);
    }
    // 计算是否应该换牌
    void AIRepOneOrDeal(List<int> dropCards, List<int> takeCards)
    {
        // 拷贝手牌
        List<int> oldCards = new List<int>(cardRecord[oppCardTable]);
        int maxScore = Utility.ScoreOfCardGroup(oldCards);
        int holdNum = oldCards.Count - 1; // 手头应该留的牌数量 仅能换1张

        // 所有可能的手牌残余
        List<List<int>> holdCardsCandidatesTemp = new List<List<int>>();
        GenerateCardsCombines(oldCards, new List<int>(), 0, holdNum, holdCardsCandidatesTemp);
        List<List<int>> holdCardsCandidates = new List<List<int>>();
        // 将可换牌堆中的牌加入到手牌中计算分数
        foreach (var hc in holdCardsCandidatesTemp)
        {
            // 每次只能加1张可换牌 生成新的列表加入
            foreach (var c in repCard)
            {
                hc.Add(c);
                holdCardsCandidates.Add(new List<int>(hc));
                hc.Remove(c);
            }
        }
        // 遍历所有可能的手牌 计算分数
        // 如果分数高于当前最高分 则更新holdCards
        List<int> newCards = new List<int>(cardRecord[oppCardTable]);
        foreach (var hc in holdCardsCandidates)
        {
            int s = Utility.ScoreOfCardGroup(hc);
            if (maxScore < s)
            {
                maxScore = s;
                newCards = hc;
            }
        }
        List<int> dropCardsCandidates = new List<int>(cardRecord[oppCardTable]);
        // 从当前手牌中删去和应有手牌中相同的部分（这部分需要保留）
        // 如果之前的搜索不能搜索到更好的结果 则dropCardsCandidates是一个空List
        foreach (var c in newCards)
        {
            if (dropCardsCandidates.Exists(x => x == c))
                dropCardsCandidates.Remove(c);
        }
        for (int i = 0; i < dropCardsCandidates.Count; i++)
            dropCards.Add(dropCardsCandidates[i]);

        dropCardsCandidates = new List<int>(cardRecord[oppCardTable]);
        // 从当前手牌中删去和应有手牌中相同的部分（这部分需要保留）
        // 如果之前的搜索不能搜索到更好的结果 则dropCardsCandidates是一个空List
        foreach (var c in dropCardsCandidates)
        {
            if (newCards.Exists(x => x == c))
                newCards.Remove(c);
        }
        for (int i = 0; i < newCards.Count; i++)
            takeCards.Add(newCards[i]);
    }
    // 生成指定数量的组合
    // cards: 可选牌
    // helpList: 用于记录当前组合的辅助变量
    // start: 当前使用的卡牌下标
    // combineNum: 组合的大小
    // combines: 输出的所有组合
    void GenerateCardsCombines(List<int> cards, List<int> helpList, int start, int combineSize, List<List<int>> combines)
    {
        if (helpList.Count == combineSize)
        {
            combines.Add(new List<int>(helpList));  // 必须复制一个LIST
            return;
        }

        for (int i = start; i < cards.Count; i++)
        {
            helpList.Add(cards[i]);
            GenerateCardsCombines(cards, helpList, i + 1, combineSize, combines);
            helpList.Remove(cards[i]);
        }

    }
    // AI主动结束的决断函数
    // AI起始的结束阈值为20（最低分），随着使用过的牌数增加，这个阈值会增大
    // 使用过的牌数量从0变化到44（2人，5手牌情况）
    // 使用线性加权法计算实时阈值: T = BASE + min(USE_NUM, 25)，T的范围是 20 - 45
    bool AIOver()
    {
        var cardUsed = 54 - PLAYER_NUMBER * MAX_CARD_HOLD - cardPile.Count; // 0 -> 44
        var T = OVER_THRESHOLD_SCORE_BASE + Math.Min(cardUsed, 25); // 最大阈值不超过45
        if (Utility.ScoreOfCardGroup(cardRecord[oppCardTable]) - MAX_CARD_HOLD * 100 >= T)
        {
            pressStatus = PressStatus.OppPressPlayer;
            repCard.Clear();
            UpdateCardsOf(repCardTable);
            aiMoveText.GetComponent<Text>().text = "电脑选择结束。";
            return true;
        }
        return false;
    }
    // AI压制的决断函数
    // AI起始的压制阈值为35（中位分），随着总牌数减少，这个阈值会增大
    // 使用过的牌数量从0变化到44（2人，5手牌情况）
    // 使用线性加权法计算实时阈值: T = BASE + min(USE_NUM/2, 14)，T的范围是 35 - 49
    void AIPress()
    {
        var cardUsed = 54 - PLAYER_NUMBER * MAX_CARD_HOLD - cardPile.Count; // 0 -> 44
        var T = PRESS_THRESHOLD_SCORE_BASE + Math.Min(cardUsed/2, 14); // 最大阈值不超过49
        if (Utility.ScoreOfCardGroup(cardRecord[oppCardTable]) - MAX_CARD_HOLD * 100 >= T)
        {
            pressStatus = PressStatus.OppPressPlayer;
            aiMoveText.GetComponent<Text>().text = "电脑选择压你。";
        }
        else
        {
            pressStatus = PressStatus.None;
            aiMoveText.GetComponent<Text>().text = "电脑选择不压你。";
        }
    }
    #endregion

}
